package arithmetique;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;

/**
 * @author Chen / Yvonnic
 *
 * The Class 'Ensemble' represent a list of financing and made their sum 
 */
public class Ensemble {

	//the list of financing, equal to the list in the UI
	private Vector<Financing> listeFinancing;

	//the list of sources, each source is a trapezoid(a sum of money) or zero
	private ArrayList<Source> listeResult;

	//the list of all x to display in the scale barre
	private ArrayList<Double> xs;
	
	/**
	 * Constructor by default
	 */
	public Ensemble() {
		listeFinancing = new Vector<Financing>();
		listeResult = new ArrayList<Source>();
		xs = new ArrayList<Double>();
	}

	/**
	 * Add a financing into the list
	 * @param f := financing : Financing
	 */
	public void addFinancing(Financing f) {
		listeFinancing.add(f);
		this.addSource(f);
	}

	/**
	 * Delete all the financing in the list
	 */
	public void deleteAll() {
		listeFinancing.clear();
		listeResult.clear();
		xs.clear();
	}

	/**
	 * Delete a financing in the list
	 * @param index := the index of the financing to be deleted : int
	 */
	public void deleteFinancing(int index) {
		listeFinancing.remove(index);
		this.calculateSum();
		setXs();
	}

	/**
	 * Calculate the result of all the financing, all sources in form of the trapezoids saved in the listeResult
	 */
	public void calculateSum() {
		listeResult.clear();
		for (int i = 0; i < listeFinancing.size(); i++) {
			addSource(listeFinancing.get(i));
		}
	}

	/**
	 * Transform a financing into 1 or 2 source, and save them into the listeResult
	 * @param f :=a financing from the listeFinancing : Financing
	 */
	public void addSource(Financing f) {
		if (listeResult.isEmpty()){
			listeResult.add(f.source1.copy());
			if (!f.sure) {
				listeResult.add(f.source2.copy());
			}
		} else {
			if (f.sure) {
				for (int i = 0; i < listeResult.size(); i++) {
					listeResult.get(i).plus(f.source1.copy());
				}
			} else {
				ArrayList<Source> listeResult2 = new ArrayList<Source>();
				for (int i = 0; i < listeResult.size(); i++) {
					listeResult2.add(listeResult.get(i).plusNew(f.source2));
					listeResult.get(i).plus(f.source1.copy());
				}
				listeResult.addAll(listeResult2);
			}	
		}
		setXs();
	}

	/**
	 * Get the peer interval among all the source in the listeResult
	 * @return := return a new interval : Interval
	 */
	public Interval getExtrema(){
		double min=0;
		double max=0;
		if (xs.size()>0){
			min = xs.get(0);
			max = xs.get(xs.size()-1);			
		}
		return new Interval(min, max);
	}

	/**
	 * For the profile of the sum of all the sources from the listeResult, form each pixel, find the correponding probability value (Y)
	 * @param nbPixel := nomber of all the pixels (support) : int
	 * @param start := start position (min support) : double
	 * @param end := end position (max support) : double
	 * @return := an array which contaoins all the Y values of the profile
	 */
	public float[] getYs(int nbPixel, double start, double end) {
		float[] ys = new float[nbPixel];
		double pas = (end - start) / nbPixel;
		float tmpMaxY;
		for(int i = 0; i < nbPixel; i++) {
			tmpMaxY = 0;
			for(int j = 0; j < listeResult.size(); j++) {
				tmpMaxY = Math.max(tmpMaxY, listeResult.get(j).getY(((double)i)*pas + start, pas));
			}
			ys[i] = tmpMaxY;
		}
		return ys;
	}

	public ArrayList<Double> getXs() {
		return xs;
	}
	/**
	 * Calculate all the special x and update xs
	 */
	private void setXs() {
		xs.clear();
		Source tmp;

		for(int i = 0; i < listeResult.size(); i++) {
			tmp = listeResult.get(i);
			if (tmp.getSupport().getMin() < tmp.getNoyau().getMin()){
				double x = tmp.getSupport().getMin();
				if (xIsMax(x, 0, false)){
					xs.add(x);
				}
			}
			if (tmp.getNoyau().getMin() < tmp.getNoyau().getMax()){
				double x = tmp.getNoyau().getMin();
				if (xIsMax(x, tmp.getProba(), true)){
					xs.add(x);
				}
			}
			{
				double x = tmp.getNoyau().getMax();
				if (xIsMax(x, tmp.getProba(), false)){
					xs.add(x);
				}
			}
			if (tmp.getSupport().getMax() > tmp.getNoyau().getMax()){
				double x = tmp.getSupport().getMax();
				if (xIsMax(x, 0, false)){
					xs.add(x);
				}
			}
		}
		Collections.sort(xs);
	}

	/**
	 * true if the point (x,y) is a special point to display in the scale bar
	 * @param x abscissa
	 * @param y possibility
	 * @param noyauMin true if (x,y) is the min of the kernel
	 * @return
	 */
	private boolean xIsMax(double x, float y, boolean noyauMin){
		int size = listeResult.size();
		int j = 0;
		boolean ismax = true;
		while (ismax && j < size){
			ismax = !listeResult.get(j).trapezoidContain(x, y, noyauMin);
			j++;
		}
		return ismax;
	}
}